package com.example.demo.cdesign.web;
/*
 *
 *
 * */
import com.opencsv.CSVReader;
import com.opencsv.CSVReaderBuilder;
import org.apache.commons.lang3.StringUtils;
import org.rosuda.REngine.REXP;
import org.rosuda.REngine.REXPMismatchException;
import org.rosuda.REngine.RList;
import org.rosuda.REngine.Rserve.RConnection;
import org.rosuda.REngine.Rserve.RserveException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.*;
import java.util.stream.Collectors;

import static com.example.demo.cdesign.CloseRserveProcessWin.findProcess;

//import org.rosuda.REngine.REngineException;
//import org.rosuda.REngine.RList;
//class arrPrint{
//    arrPrint() {}
//    public void arrPrint(double input[][]){//输出二维数组
//        for(int i = 0;i<input.length;i++) {
//            System.out.println(Arrays.toString(input[i]));
//        }
//    }
//}
//class TwoDimArr{
//      TwoDimArr(){};
//      public  String[][] TwoDimArr(String[] onestr,int collen){
//          int j = onestr.length/collen;//每列有多少个？=矩阵有多少行。
//          String twodimarr[][] = new String[j][collen];
//          for(int i = 0;i < collen;i++) {
//              twosimarr[][i] = onstr[(j*i+1):((j*(i+1))];
//          }
//          return  twodimarr;
//      }
//}

@Component
public class JavaR {

    @Value("${model.wd}")
    private String WD;
    @Value("${model.csv}")
    private String CSV_PATH;

    public  boolean rserveRun = false;
    public  RConnection rc = null;
    public  Properties props = System.getProperties();

    public  String killServe(RConnection rc) throws RserveException, REXPMismatchException {
//        RConnection rEngine = null;
        int rServePid = -1;
        try {
            rServePid = rc.eval("Sys.getpid()").asInteger();
        } catch (REXPMismatchException e) {
            e.printStackTrace();
        } catch (RserveException e) {
            e.printStackTrace();
        }
//        rEngine = rc;
        System.out.println(rc.eval("print(\"some consuming code...\")").asString());
        // Terminate.
        RConnection c2 = new RConnection();
        // SIGTERM might not be understood everywhere: so using SIGKILL signal, as well.
        c2.eval("tools::pskill(" + rServePid + ")");
        System.out.println(c2.eval("print(\"==== some consuming code...\")").asString());
        c2.eval("tools::pskill(" + rServePid + ", tools::SIGKILL)");
        c2.close();
        return "the rc-process has been killed!";
    }

    public  String shutDown(RConnection rc) throws RserveException {
        rc.shutdown();
        return "this port Rserve process has been shutdowned";
    }
    public  boolean stop() {
        if(props.getProperty("os.name").contains("Windows")){
            return findProcess("Rserve.exe");
        }
        else {
            List<String> PIDS = CloseRserveProcess.getPID("Rserve");
            return CloseRserveProcess.closeLinuxProcess(PIDS);
        }
    }
    public  boolean start() {
        if(props.getProperty("os.name").contains("Windows")){
           findProcess("Rserve.exe");
        }
        else {
            List<String> PIDS = CloseRserveProcess.getPID("Rserve");
            CloseRserveProcess.closeLinuxProcess(PIDS);
        }
        return StartRserver.checkLocalRserve();
    }


    public  REXP runR_upd() {
//        RConnection rc = null;

        try {
            rc = new RConnection();//rc对象
            boolean upd = false;
//        String data_source_path = null;
//        String newdata_path = null;
//        boolean saver_data = true;
            rc.eval("setwd(\"" + WD + "\")");//指定workdirectory(工作环境)。
            rc.eval("load(\"./java_R.RData\")");//加载已经保存的RData。
            rc.eval("source(\"./DataUpdate.R\")");
//        REXP rexp3=rc.eval("myFunc3(\"" + CSV_PATH + "NO12_1219-zhuliushijianwrong-total-small.csv\")");
//        Matrix m = new Matrix(rexp3.asDoubleMatrix());
            if (upd) {
                REXP rexp_upd = rc.eval("DataUpdate(data_source_path = FALSE"
                        + ",newdata_path = \"" + CSV_PATH + "NO12_1219-zhuliushijianwrong-total-added.csv\",save_rdata = FALSE)");
                rc.eval("save.image(\"./java_R.RData\")");//保存RData
                return rexp_upd;
            } else {
                REXP rexp_upd = rc.eval("DataUpdate(data_source_path = \"" + CSV_PATH + "NO12_1219-zhuliushijianwrong-total-small.csv\""
                        + ",newdata_path = FALSE,save_rdata = TRUE)");
                rc.eval("save.image(\"./java_R.RData\")");//保存RData
                return rexp_upd;
            }
        } catch (RserveException e) {
            e.printStackTrace();
            return null;
        } finally {
            if (rc != null) {
                rc.close();
            }
        }
    }

    public  List<Map> runR_shd(String fpd_from, String fpd_end, String unitCode) throws REXPMismatchException {
//        RConnection rc = null;
        start();
        try {
            rc = new RConnection();//rc对象
            rc.eval("print(12324)");
            rc.eval("setwd(\"" + WD + "\")");//指定workdirectory(工作环境)。
            rc.eval("load(\"./java_R.RData\")");//加载已经保存的RData。
//            rc.eval("source(\"./ToSQL.R\")");
//            rc.eval("rn = ToSql()");
            REXP rexp_shd = rc.eval("ToSql(fpd_from=" + fpd_from + ",fpd_end=" + fpd_end + ",unitCode=\""+unitCode+"\")");
//            rc.eval("save.image(\"./java_R.RData\")");//保存RData,如果只是查看数据，没有处理数据，可以不用save
//            rexp_shd.asList();
            RList rl1 = rexp_shd.asList();
            List<Object> data_name = new ArrayList<>();
            List<Map> listmap = new ArrayList<>();
            for (int j = 0; j < rl1.at(0).length()-1; j++) {
                Map<String, Object> map = new LinkedHashMap<>();
                for (int i = 0; i < rl1.names.size()-1; i++) {
                    map.put(rl1.names.get(i).toString(), rl1.at(i).asStrings()[j]);
                }
                listmap.add(map);
            }
            data_name.add(listmap);
            Map<Object, String> namemap = new LinkedHashMap();
            for (Object onekey : rl1.names) {
                String onekey_str = (String) onekey;
//                System.out.println(onekey_str);
                if (onekey_str.contains("FPD")) {
                    namemap.put(onekey_str, "满功率日");
//                    System.out.println("yes");
                } else if (onekey_str.contains("CALBCONCENTRATION")) {
                    namemap.put(onekey_str, "计算出的硼浓度");
                } else if (onekey_str.contains("INITAVGLVL_DELTA")) {
                    namemap.put(onekey_str, "平均液位偏差");
                } else if (onekey_str.contains("ZONEINITLVLDEV_")) {
                    namemap.put(onekey_str, StringUtils.substringAfter(onekey_str, "_") + "区初始液位");
                } else if (onekey_str.contains("ZONEINITLVLDEV_DELTA_")) {
                    namemap.put(onekey_str, StringUtils.substringAfter(onekey_str, "_") + "区液位偏差");
                } else if (onekey_str.contains("PMRERGAIN_")) {
                    namemap.put(onekey_str, StringUtils.substringAfter(onekey_str, "_") + "反应性增益");
                } else if (onekey_str.contains("PMAVGODBURNUP_")) {
                    namemap.put(onekey_str, StringUtils.substringAfter(onekey_str, "_") + "平均出口卸料燃耗");
                } else if (onekey_str.contains("PMMBP_")) {
                    namemap.put(onekey_str, StringUtils.substringAfter(onekey_str, "_") + "最大棒束功率");
                } else if (onekey_str.contains("CHRESIDENCETIME_")) {
                    namemap.put(onekey_str, StringUtils.substringAfter(onekey_str, "_") + "通道驻留时间");
                } else if (onekey_str.contains("RELOAD_")) {
                    namemap.put(onekey_str, StringUtils.substringAfter(onekey_str, "_") + "换料一");
                } else if (onekey_str.contains("RELOAD2_")) {
                    namemap.put(onekey_str, StringUtils.substringAfter(onekey_str, "_") + "换料二");
                } else if (onekey_str.contains("FPD_POWER_")) {
                    namemap.put(onekey_str, StringUtils.substringAfter(onekey_str, "_") + "当前功率");
                } else if (onekey_str.contains("NEXT_POWER_")) {
                    namemap.put(onekey_str, StringUtils.substringAfter(onekey_str, "_") + "下一功率");
                }
            }
            data_name.add(namemap);
            return listmap;
        } catch (RserveException e) {
            e.printStackTrace();
            return null;
        } finally {
            if (rc != null) {
                rc.close();
            }
        }
    }


    public  REXP runR_rem(String modelStart, String modelEnd, String taskId) throws RserveException, REXPMismatchException {
//        RConnection rc = null;
        try {
            rc = new RConnection();//rc对象
            rc.eval("setwd(\"" + WD + "\")");//指定workdirectory(工作环境)。
            rc.eval("load(\"./java_R.RData\")");//加载已经保存的RData。
            rc.eval("source(\"./Remodelling.R\")");
            rserveRun = rc.isConnected();

            REXP rexp_rem = rc.eval("Remodelling(local_data = TRUE"
                    + ",local_path = \"" + WD + "totaldata_bynow_remodellneed.csv\"" +
                    ",save_rdata = FALSE,model_start=\""  + modelStart + "\",model_end=\"" + modelEnd + "\",task_ID=\"" + taskId + "\")");
            rc.eval("save.image(\"./java_R.RData\")");//保存RData
            return rexp_rem;
        } catch (RserveException e) {
            e.printStackTrace();
            return null;
        } finally {
            if (rc != null) {
                rc.close();
                rserveRun = rc.isConnected();
            }
        }
    }

    public  String[] getFpd() {
        String srcPath = "/Users/wangdeying/Downloads/RWD/java_R/totaldata_bynow_remodellneed.csv";
        String charset = "utf-8";
        List<String> lstr = new ArrayList<>();
        try (CSVReader csvReader = new CSVReaderBuilder(new BufferedReader(new InputStreamReader(new FileInputStream(new File(srcPath)), charset))).build()) {
            Iterator<String[]> iterator = csvReader.iterator();
            while (iterator.hasNext() && iterator.next()[1] != "FPD") {//因为csv文件里面含有表头，所以FPD列组成的数组里面多了一个“FPD”，需要在add的时候去除
                lstr.add(iterator.next()[1]);
//                Arrays.stream(iterator.next()).forEach(System.out::print);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        String[] strs = new String[lstr.size()];
        String[] lsTostrs = lstr.toArray(strs);
        Arrays.sort(lsTostrs, Collections.reverseOrder());
        return lsTostrs;
    }

    public  REXP runR_shm() throws RserveException, REXPMismatchException {
//        RConnection rc = null;
        try {
            rc = new RConnection();//rc对象
            rc.eval("setwd(\"" + WD + "\")");//指定workdirectory(工作环境)。
            rc.eval("load(\"./java_R.RData\")");//加载已经保存的RData。
            rc.eval("source(\"./Showmodels.R\")");
            REXP rexp_shm = rc.eval("Showmodels()");
            rc.eval("save.image(\"./java_R.RData\")");//保存RData
            return rexp_shm;
        } catch (RserveException e) {
            e.printStackTrace();
            return null;
        } finally {
            if (rc != null) {
                rc.close();
            }
        }
    }

    public  REXP runR_Pre(Double fpd, String channels, Double yewei_avg, String[] list1, String[] list2
            , String avgburnup, String chp, String taskID) {
        //        RConnection rc = null;
        /*下面四个语句将list1与list2转换为字符串并截取PowerPre所需要的部分*/
        start();
        String list1_s = Arrays.toString(list1);
        String list1_ss = list1_s.substring(1, list1_s.indexOf("]"));
        String list2_s = Arrays.toString(list2);
        String list2_ss = list2_s.substring(1, list2_s.indexOf("]"));

        try {
            rc = new RConnection();
            rc.eval("setwd(\"" + WD + "\")");
            rc.eval("load(\"./java_R.RData\")");
//            rc.eval("source(\"./PowerPre.R\",encoding = \"UTF-8\")");
            REXP rexp_pre = rc.eval("PowerPre(fpd = " + fpd + ",reload_channels=\"" + channels + "\"," +
                    "yewei_avg=" + yewei_avg + "," +
                    "yewei_14=list(" + list1_ss + ")," +
                    "yewei_delta=list(" + list2_ss + ")," +
                    "avgburnup=\""+avgburnup+"\","+
                    "chp=\""+chp+"\","+
                    "save_rdata = FALSE,task_ID=\""+taskID+"\")");
            rc.eval("save.image(\"./java_R.RData\")");//保存RData
            return rexp_pre;
        } catch (RserveException e) {
            e.printStackTrace();
            return null;
        } finally {
            if (rc != null) {
                rc.close();
            }
        }
    }

    public  String[][] twoDim(String[] oneDim, int l) {//该方法将一维数组变为切分为二维数组。
        int num = oneDim.length / l;
        String[][] arr = new String[num][l];//num个长度为「ondDim.length/num」的一维数组组成。
        for (int i = 0; i < num; i++) {
            arr[i] = Arrays.copyOfRange(oneDim, l * i, l * (i + 1));
        }
        return arr;
    }

    public  String[][] tDim(String[][] arr) {//该方法用来对二维数组进行转置处理。
//        String media;
        int l = arr.length;
        int num = arr[0].length;
        String[][] arr_copy = new String[num][l];
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[0].length; j++) {
//                media = arr[i][j];
                arr_copy[j][i] = arr[i][j];
//                arr[j][i] = media;

            }
        }
        return arr_copy;
    }

    public  List<String> getFile(String taskId) {
//        String id = "01";
        List<String> boo = new ArrayList<>();
        File baseDir = new File(WD + "channel_models");//进入380个通道文件夹上一层文件夹
        if (!baseDir.exists()) {
            if (!baseDir.mkdir()) return boo;
        }
        File[] dirs = baseDir.listFiles();//列出380个通道文件夹，只能含有通道类文件夹
        if (dirs == null) return boo;//判断
        List<File> list = Arrays.stream(dirs).sorted(Comparator.comparing(File::getName)).collect(Collectors.toList());//对380个通道文件夹进行排序
        for (File dir : list) {//遍历
            if (!dir.isDirectory()) continue;//判断
            File[] files = dir.listFiles();//进入某个通道文件夹后，得到该文件夹的文件列表
            if (files == null) continue;//判断
            for (File file : files) {
                if (!file.isFile() || !file.getName().matches(taskId + "_" + "[A-Z]\\d{2}" + "\\.RData")) continue;//判断
                String channel_name = StringUtils.substringBetween(file.getName(), "_", ".");
                boo.add(channel_name);
            }
        }
        return boo;
    }

    public  boolean deleteFiles(String taskId, boolean ctnue) {
        boolean success = true;
        File baseDir = new File(WD + "channel_models");//进入380个通道文件夹上一层文件夹
        if (!baseDir.exists() || !baseDir.isDirectory()) return false;
        File[] dirs = baseDir.listFiles();//列出380个通道文件夹，只能含有通道类文件夹
        if (dirs == null) return false;
        for (File dir : dirs) {//遍历
            if (!dir.isDirectory()) continue;//判断
            File[] files1 = dir.listFiles();//进入某个通道文件夹后，得到该文件夹的文件列表
            if (files1 == null) continue;//判断
            if (ctnue == false) {
                for (File file : files1) {
                    if (!file.isFile() || !file.getName().matches(taskId + "_" + "[A-Z]\\d{2}" + "\\.RData"))
                        continue;//判断
                    success = success && file.delete();
                }
            }
            File[] files2 = dir.listFiles();//删除相同taskId的文件后再继续查找
            if (files2 == null) continue;//判断
            if (files2.length > 2) {
                Arrays.sort(files2, (o1, o2) -> o2.getName().compareTo(o1.getName()));
                for (int i = 2; i < files2.length; i++) {
                    success = success && files2[i].delete();
                }
            }
        }
        return success;
    }

}


